package org.xm.sk.config;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.MultipartConfigElement;

import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.xm.sk.common.HttpClientUtils;
import org.xm.sk.common.XmlProcessor;
import org.xm.sk.module.IdBitWorker;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.Tag;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
@EnableAutoConfiguration(exclude = { MultipartAutoConfiguration.class })
public class WebMvcConfig implements WebMvcConfigurer {

    @Value("${jwt.header}")
    private String header;
    @Value("${jwt.tokenHead}")
    private String tokenHeader;
    @Value("${spring.jackson.date-format}")
    private String dateFormat = "yyyy-MM-dd HH:mm:ss";
    @Value("${spring.http.multipart.max-file-size}")
    private String maxFileSize = "400KB";
    @Value("${spring.http.multipart.max-request-size}")
    private String maxRequestSize = "4000KB";

    // @Autowired
    // private Environment env;

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/")
                .setViewName("redirect:/swagger-ui.html");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedHeaders("*").allowedOrigins("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE",
                        "OPTIONS")
                .allowCredentials(false).maxAge(3600);
    }

    @Bean
    public XmlProcessor getHandler() {
        XmlProcessor handler = new XmlProcessor();
        handler.setMarshaller(getCastorMarshaller());
        handler.setUnmarshaller(getCastorMarshaller());
        return handler;
    }

    @Bean
    public Jaxb2Marshaller getCastorMarshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("org.xm.sk.vo");
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("jaxb.formatted.output", true);
        map.put("jaxb.encoding", "UTF-8"); // 设置xml编码
        jaxb2Marshaller.setMarshallerProperties(map);
        return jaxb2Marshaller;
    }

    @Bean
    public Docket createRestApi() {
        ParameterBuilder tokenPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<Parameter>();
        tokenPar.name(header).description("令牌")
                .defaultValue(tokenHeader + "token")
                .modelRef(new ModelRef("string")).parameterType("header")
                .required(true).build();
        pars.add(tokenPar.build());
        return new Docket(DocumentationType.SWAGGER_2)
                .globalOperationParameters(pars).apiInfo(apiInfo())
                .tags(new Tag("hello", "欢迎测试相关"), getTags()).select()
                .apis(RequestHandlerSelectors
                        .basePackage("org.xm.sk.controller"))
                .paths(PathSelectors.any()).build();
    }

    private Tag[] getTags() {
        Tag[] tags = { new Tag("auth", "鉴权相关"), new Tag("activity", "活动相关"),
                new Tag("brand", "品牌相关"), new Tag("coupon", "优惠券相关"),
                new Tag("hairdresser", "发型师相关"), new Tag("image", "图片相关"),
                new Tag("item", "项目相关"), new Tag("mete", "评论相关"),
                new Tag("order", "订单相关"), new Tag("organ", "机构相关"),
                new Tag("price", "价格相关"), new Tag("role", "角色相关"),
                new Tag("shop", "门店相关"), new Tag("user", "用户相关"),
                new Tag("works", "作品相关"), new Tag("server_time", "服务时间相关") };
        return tags;
    }

    private ApiInfo apiInfo() {
        StringBuffer out = new StringBuffer();
        try {
            Resource resource = new ClassPathResource("instructions.itr");
            InputStream input = resource.getInputStream();
            byte[] b = new byte[4096];
            for (int n; (n = input.read(b)) != -1;) {
                out.append(new String(b, 0, n, "UTF-8"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ApiInfoBuilder().title("闪电科技项目RESTful APIs接口服务")
                .description(out.toString())
                .termsOfServiceUrl("https://github.com/lightechnology")
                .contact(
                        new Contact("闪电科技", "https://github.com/lightechnology",
                                "adolphus520@163.com"))
                .version("1.0").build();
    }

    @Bean
    @ConditionalOnMissingBean({ RestOperations.class, RestTemplate.class })
    public RestOperations restOperations() {
        CloseableHttpClient httpClient = null;
        try {
            httpClient = HttpClientUtils.acceptsUntrustedCertsHttpClient();
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (KeyStoreException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
                httpClient);

        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);

        // 使用 utf-8 编码集的 conver 替换默认的 conver（默认的 string conver 的编码集为
        // "ISO-8859-1"）
        List<HttpMessageConverter<?>> messageConverters = restTemplate
                .getMessageConverters();
        Iterator<HttpMessageConverter<?>> iterator = messageConverters
                .iterator();
        while (iterator.hasNext()) {
            HttpMessageConverter<?> converter = iterator.next();
            if (converter instanceof StringHttpMessageConverter) {
                iterator.remove();
            }
        }
        messageConverters
                .add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return restTemplate;
    }

    @Bean
    public IdBitWorker idBitWorker() {
        return new IdBitWorker();
    }
    
    /*@Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
        tomcat.addAdditionalTomcatConnectors(createHttpConnector());
        return tomcat;
    }

    private Connector createHttpConnector() {
        Integer port = Integer.valueOf(env.getProperty("http.port"));
        Connector connector = new Connector(
                "org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(port);
        connector.setSecure(false);
        return connector;
    }*/

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer initJackson() {
        Jackson2ObjectMapperBuilderCustomizer c = new Jackson2ObjectMapperBuilderCustomizer() {
            @Override
            public void customize(Jackson2ObjectMapperBuilder builder) {
                builder.serializationInclusion(JsonInclude.Include.NON_NULL);
                builder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
                // 自定义Long类型转换 超过12个数字用String格式返回，由于js的number只能表示15个数字
                builder.serializerByType(Long.class, new CustomLongConverter());
                builder.serializerByType(Long.TYPE, new CustomLongConverter());
                // Double数据四舍五入保留两位小数
                // builder.serializerByType(Double.class, new
                // CustomDoubleConverter());
                // builder.serializerByType(Double.TYPE, new
                // CustomDoubleConverter());
            }
        };
        return c;
    }

    class CustomLongConverter extends StdSerializer<Long> {

        private static final long serialVersionUID = -512375730233764287L;

        public CustomLongConverter() {
            super(Long.class);
        }

        @Override
        public void serialize(Long value, JsonGenerator gen,
                SerializerProvider serializers)
                throws IOException, JsonProcessingException {
            if (value.toString().length() > 12) {
                gen.writeString(value.toString());
            } else {
                gen.writeNumber(value);
            }
        }
    }

    class CustomDoubleConverter extends StdSerializer<Double> {

        private static final long serialVersionUID = -512375730233764287L;

        public CustomDoubleConverter() {
            super(Double.class);
        }

        @Override
        public void serialize(Double value, JsonGenerator gen,
                SerializerProvider serializers)
                throws IOException, JsonProcessingException {
            String v = String.format("%.2f", value);
            if (v.toString().length() > 12) {
                gen.writeString(v);
            } else {
                gen.writeNumber(v);
            }
        }
    }

    /**
     * 文件上传配置
     * 
     * @return
     */
    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        // 文件最大
        factory.setMaxFileSize(maxFileSize); // KB,MB
        /// 设置总上传数据总大小
        factory.setMaxRequestSize(maxRequestSize);
        return factory.createMultipartConfig();
    }

    @Bean
    public Converter<String, Date> stringToDateConverter() {
        return new StringToDateConverter();
    }

}
